#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"//分割字符串
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

int lastcode = 0;//保留退出码
int quit = 0;//作为死循环的条件
extern char **environ;//环境变量的声明
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];//保存分割的字符串，模拟命令行参数
char pwd[LINE_SIZE];


//自定义本地环境变量表，内部维护自己环境变量

char myenv[LINE_SIZE];

const char *getusername()//获取用户名
{
  return getenv("USER");
}

const char *gethostname()//获取主机名
{
  return getenv("HOSTNAME");
}

void getpwd()//获取当前路径
{
  getcwd(pwd,sizeof(pwd));//通过getcwd获取当前工作目录的完整路径，放在pwd数组中
}

void interact(char *cline,int size)
{
  getpwd();
  printf(LEFT"%s@%s %s"RIGHT""LABLE"",getusername(),gethostname(),pwd);
  char *s = fgets(cline,size,stdin);//读取一行，但是也会读取回车符
  assert(s);//如果不为空，就继续往下走
  (void)s;
  //将最后的回车符变成\0
  cline[strlen(cline) - 1] = '\0';
}


int splitstring(char cline[],char*_argv[])
{
  int i  = 0;
  argv[i++] = strtok(cline,DELIM);//遇到DELIM符号停下
  while(_argv[i++] = strtok(NULL,DELIM));
  return i -1;//因为最后一次i也++了，但是没有放任何数
}

void normalexcute(char *_argv[])

{
  pid_t id = fork();
  if(id < 0)
  {
    perror("fork");
    return;
  }
  else if(id == 0)
  {
    //让子进程执行命令
    execvp(_argv[0],_argv);//第一个参数是文件名字，第二个执行的参数命令
    exit(EXIT_CODE);//如果执行了excvp就不会执行这句
  }else//父进程等待子进程
  {
    int status = 0;//输出型参数
    pid_t ret = waitpid(id,&status,0);
    if(ret == id){
      lastcode = WEXITSTATUS(status);//获取退出码
    }
  }
}

int buildcommand(char*_argv[],int _argc)
{
  if(_argc == 2 &&strcmp(_argv[0],"cd") == 0)//如果当前命令是cd,得有两个子串
  {
    chdir(argv[1]);
    getpwd();
    sprintf(getenv("PWD"),"%s",pwd);
    return 1;
  }
  else if(_argc == 2 && strcmp(_argv[0],"export") == 0)
  {
    strcpy(myenv,_argv[1]);//将要导入的环境变量放在自己要维护的参数表
    putenv(myenv);
    return 1;
  }
  else if(_argc == 2 && strcmp(_argv[0],"echo") == 0)
  {
    if(strcmp(_argv[1],"$?") == 0)//查看上一次的退出码
    {
      printf("%d\n",lastcode);
      lastcode = 0;//每次用完重新置零
    }
    else if(*argv[1] == '$'){
      char *val = getenv(_argv[1] + 1);
      if(val) printf("%s\n",val);
    }
    else{
      printf("%s\n",_argv[1]);
    }
    return 1;
  }


  if(strcmp(_argv[0],"ls")== 0)
  {
    _argv[_argc++] = "--color";
    _argv[_argc]= NULL;
  }
  return 0;

}


int main()
{
  while(!quit)
  {
      //1.
      //2.交互问题，获取命令行
      interact(commandline,sizeof(commandline));
      //3.字串分割问题，解析命令
      int argc = splitstring(commandline,argv);//分割字符串，放在argv指针数组中
      if(argc == 0) continue;
      
      //debugcode
    //  for(int  i = 0; argv[i]; i ++) printf("[%d]:%s\n",i,argv[i]);
      //4.指令的判断
     int n = buildcommand(argv,argc);
      

      //5.普通命令的执行
     if(!n) normalexcute(argv);
  }


  return 0;
}
